import os
import time
import unittest
from typing import Union, Dict

from appium.webdriver import WebElement
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.extensions.android.nativekey import AndroidKey
from appium.webdriver.webdriver import WebDriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from common import time_util, global_util
from config.constants import Constants


class BasePage(unittest.TestCase):
    """
    页面公共属性，方法
    """

    def __init__(self):
        # 使用unittest断言
        unittest.TestCase.__init__(self)
        self.driver: WebDriver = global_util.get_value(Constants.KEY_DRIVER)
        self.img_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + '/report/screenshots/'

    # 输入
    def input(self, loc, value):
        self.driver.find_element(loc).send_keys(value)

    # 查找是否存在该元素并点击（若存在多个点击第一个）
    def find_click(self, loc):
        els = self.driver.find_elements(*loc)
        if els:
            els[0].click()
            return True
        return False

    def swipe_ratio(self, start_x, start_y, end_x, end_y, duration):
        """
        按屏幕比例滑动
        例如 左滑 swipe(0.9,0.5,0.3,0.5,1000)
        :param start_x: 起点x轴占屏幕比例
        :param start_y: 起点y轴占屏幕比例
        :param end_x:   起点x轴占屏幕比例
        :param end_y:   起点x轴占屏幕比例
        :param duration:滑动时间
        """
        window_size = self.driver.get_window_size()
        x = window_size["width"]
        y = window_size["height"]
        self.driver.swipe(x * start_x, y * start_y, x * end_x, y * end_y, duration)

    def swipe_no_release(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0):
        """滑动后不释放焦点，调用完任意点击界面，完成释放操作
        例如：driver.tap([(300, 300)])"""
        actions = ActionChains(self.driver)
        actions.w3c_actions = ActionBuilder(self.driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
        actions.w3c_actions.pointer_action.move_to_location(start_x, start_y)
        actions.w3c_actions.pointer_action.pointer_down()
        actions.w3c_actions.pointer_action.pause(duration / 1000)
        actions.w3c_actions.pointer_action.move_to_location(end_x, end_y)
        # actions.w3c_actions.pointer_action.release()
        actions.perform()

    # 返回
    def back(self):
        self.driver.press_keycode(AndroidKey.BACK)
        time.sleep(1)

    def find_ele_click(self, by: str = AppiumBy.ID, value: Union[str, Dict] = None):
        """
        查找元素，得到一个元素，然后，执行点击操作
        :param by:
        :param value:
        """

        try:
            self.driver.find_element(by, value).click()
        except BaseException as e:
            print("exception is %s in find_ele_click" % e)

    def find_eles_and_ind_then_click(self, by: str = AppiumBy.ID, value: Union[str, Dict] = None, index: int = 0):
        """
        查找元素，得到一个列表，然后，根据索引查询得到该元素，最后，执行点击操作
        :param by:
        :param value:
        :param index:
        """
        try:
            self.driver.find_elements(by, value)[index].click()
        except BaseException as e:
            print("exception is %s in find_eles_and_ind_then_click" % e)

    def wait_until_invisible(self, timeout, locator):
        """
        在预期的时间内等待元素隐藏，元素隐藏后，函数立即返回；超时后，元素依旧出现，抛出超时错误
        :param timeout:
        :param locator:
        """
        try:
            WebDriverWait(self.driver, timeout).until(
                EC.invisibility_of_element_located(locator))
        except BaseException as e:
            print("exception is %s in wait_until_invisible" % e)
            return False
        else:
            return True

    def wait_until_visible(self, timeout, locator):
        """
        在预期的时间内等待元素出现，元素出现后，函数立即返回；超时后，元素依旧无出现，抛出超时错误
        :param timeout:
        :param locator:
        """
        try:
            WebDriverWait(self.driver, timeout).until(
                EC.visibility_of_element_located(locator))
        except BaseException as e:
            print("exception is %s in wait_until_visible" % e)
            return False
        else:
            return True

    def find_eles_and_ind_then_gettext(self, by: str = AppiumBy.ID, value: Union[str, Dict] = None, index: int = 0):
        """
         查找元素，得到一个列表，然后，根据索引查询得到该元素，最后，获取文本
         :param by:
         :param value:
         :param index:
        """
        try:
            return self.driver.find_elements(by, value)[index].text
        except BaseException as e:
            print("exception is %s in find_eles_and_ind_then_gettext" % e)

    def is_main_activity(self):
        """
        是否是首页
        """
        return "MainActivity" in self.driver.current_activity

    # 返回首页
    def back_main_activity(self):
        """
        返回首页
        """
        while not self.is_main_activity():
            self.back()

    def screenshot(self, folder_name, file_name, add_time_suffix=True):
        """
        截图
        :param folder_name: 截图文件夹名
        :param file_name: 截图文件名
        :param add_time_suffix: 截图文件名是否添加时间后缀
        :return: 有IO异常返回 False,否则返回 True
        """
        # 截图存放的公共路径
        path_screenshots = global_util.get_value(Constants.KEY_SCREENSHOTS)
        path_file = path_screenshots + folder_name
        if not os.path.exists(path_file):
            os.makedirs(path_file)

        if add_time_suffix:
            screen_save_path = f"{path_file}/{file_name}_{time_util.curDatetimeSuffix()}.png"
        else:
            screen_save_path = f"{path_file}/{file_name}.png"
        return self.driver.get_screenshot_as_file(screen_save_path)

    def wait_data_load(self):
        """
        等待页面所有数据加载完成
        page_source获取到页面源码，页面在加载数据时源码都是在持续更新的，当页面数据加载完成时源码就不会再更新
        """
        old_page = ''
        new_page = self.driver.page_source
        while old_page != new_page:
            time.sleep(0.3)
            old_page = new_page
            new_page = self.driver.page_source

    def click_mask(self):
        """点击导航遮罩"""
        view_guide = (By.ID, "view_guide")
        self.find_click(view_guide)

    @staticmethod
    def sleep(seconds):
        time.sleep(seconds)

    @staticmethod
    def getBounds(web_element: WebElement):
        """
        获取元素的范围边界，前两个为左上坐标，后两个为右下坐标 例如：
        ['29', '592', '310', '656', '']"""
        bounds = web_element.get_attribute("bounds")
        return bounds.replace("[", "").replace("]", ",").split(",")

    def switchNative(self):
        """从 Webview上下文 切换为 Native上下文"""
        self.driver.switch_to.context('NATIVE_APP')

    def switchWebview(self):
        """从 Native上下文 切换为 Webview上下文"""
        self.driver.switch_to.context('WEBVIEW_'+self.driver.current_package)
